package com.yiji.openapi;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.UUID;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;

import org.apache.commons.codec.digest.DigestUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.conn.ssl.X509HostnameVerifier;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.SingleClientConnManager;
import org.apache.http.params.CoreConnectionPNames;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.collect.Maps;
import com.suixun.dao.LogyijinotifyMapper;
import com.suixun.entity.Logyijinotify;
import com.suixun.service.Constants;
import com.yiji.openapi.DigestUtil.DigestALGEnum;

/**
 * 该Demo展示了如何请求易极付服务<br>
 * 如果要将该demo应用于实际场景，可以将main方法切换到web请求处理代码中。<br>
 * 
 * @author lucas
 * 
 */
public class HttpRequest {
    @Resource
    private LogyijinotifyMapper lynm;
    private static LogyijinotifyMapper logyijinotifyMapper;  
    private static Logger logger = LoggerFactory.getLogger(HttpRequest.class);
    @PostConstruct  
    public void init() {  
        HttpRequest.logyijinotifyMapper = lynm;
    }  
    /**
     * Demo的入口，在实际使用时，如果是web环境应该是类似这样的处理代码(使用spring-mvc框架)：
     * 
     * <pre>
	 * 	@RequestMapping(value = "query", method = RequestMethod.POST)
		public String query(DataForm dataForm, HttpServletRequest request,
						HttpServletResponse response, ModelMap modelMap) {
						//业务处理
		}
	 * </pre>
     * 
     * @param args
     */
    public static void main(String[] args) {
        // 组装参数
        Map<String, String> params = initParams();

        // 发送请求
        String responseMessage = exchange(params);

        // 反序列化数据
        @SuppressWarnings("unchecked")
        HashMap<String, String> resultMap =
                JsonMapper.nonDefaultMapper().fromJson(responseMessage, HashMap.class);

        // 后续业务操作
        logger.info("输出结果：{}", resultMap);
    }

    /**
     * 初始化参数 <br/>
     * 在web环境下，业务参数是由页面传入的。<br/>
     * 实际的例子如：
     * 
     * <pre>
	 * 		<!DOCTYPE html>
				<html>
				<head>
				<meta charset="UTF-8">
				<title>查询信息</title>
				</head>
				<body>
					<form action="/query.htm" method="post" name="queryForm">
							会员ID：<input name="userId" /> <br/>
							起始时间：<input name="beginDate" /> <br/>
							结束时间：<input name="endDate" /> <br/>
					</form>
				</body>
				</html>
	 * </pre>
     * 
     * 后台处理代码将接受到请求参数，此处忽略了以上步骤，直接使用params.put(key,value)来模拟。
     * 
     * @return
     */
    private static Map<String, String> initParams() {

        Map<String, String> params = Maps.newHashMap();
        // 基本参数
        // 这部分参数对于一个商户而言是固定的
        String orderno = DigestUtils.md5Hex(UUID.randomUUID().toString());
        params.put(ApiConstants.ORDER_NO, orderno);
        params.put(ApiConstants.PARTNER_ID, Constants.get_partner_id());
        params.put(ApiConstants.PROTOCOL, Constants.HTTP_POST_PROTOCOL);
        params.put(ApiConstants.SIGN_TYPE, Constants.SIGN_TYPE);
        params.put(ApiConstants.NOTIFY_URL, Constants.get_notify_url());
        params.put(ApiConstants.RETURN_URL, Constants.RETURN_URL);

        // /////////////签约查询
        /*
         * params.put(ApiConstants.SERVICE, "yxtDeduct"); params.put("contractNo",
         * "20150826000200034782"); params.put("totalAmount", "0.01"); params.put("externalOrderNo",
         * orderno); params.put("costComposition", "{\"手表激活费用\":\"0.01\"}"); params.put("memo",
         * "随寻代扣");
         */
        // //////////////////////签约
        // 业务参数
        // 每个服务的业务参数是不同的
        // 具体请参考文档的请求参数
        params.put(ApiConstants.SERVICE, "yxtDeductSign");
        params.put("serviceCode", "PUBLIC_HOUSING");
        params.put("realName", "aaa");
        params.put("certNo", "330726198802022711");
        params.put("certValidTime", "0");
        params.put("mobileNo", "13868113229");
        params.put("profession", "");
        params.put("bankCardType", "DEBIT_CARD"); // DEBIT_CARD:借记卡 CREDIT_CARD:信用卡
        params.put("bankCode", "ABC");
        params.put("bankCardNo", "6228480322877618916");

        params.put("certBackImageUrl", "1");
        params.put("memo", "qianyuedaikou");
        params.put("withholdContractNo", "0000000000");
        params.put("address", "hangzhou");
        params.put("bankCardImageUrl", "1");
        params.put("profession", "1");
        params.put("withholdContractImageUrl", "daikouhetong");
        params.put("certFrontImageUrl", "1");
        return params;
    }

    /**
     * 请求服务并返回信息
     * 
     * @param parameters
     * @return
     */
    protected static String exchange(Map<String, String> parameters) {
        HostnameVerifier hostnameVerifier = org.apache.http.conn.ssl.SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER;
        HttpClient client = new DefaultHttpClient();
        SchemeRegistry registry = new SchemeRegistry();
        SSLSocketFactory socketFactory = SSLSocketFactory.getSocketFactory();
        socketFactory.setHostnameVerifier((X509HostnameVerifier) hostnameVerifier);
        registry.register(new Scheme("https", socketFactory, 443));
        SingleClientConnManager mgr = new SingleClientConnManager(client.getParams(), registry);
        DefaultHttpClient httpClient = new DefaultHttpClient(mgr, client.getParams());
        HttpsURLConnection.setDefaultHostnameVerifier(hostnameVerifier);
        // 请求超时
        client.getParams().setParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, 20000);
        // 读取超时
        client.getParams().setParameter(CoreConnectionPNames.SO_TIMEOUT, 20000);
        HttpPost post = new HttpPost(Constants.get_openapi_address());

        try {
            String sign =
                    DigestUtil.digest(parameters, Constants.get_sercurity_key(), DigestALGEnum.MD5,
                            "UTF-8");

            String requestString = buildPairs(parameters, sign);
            Logyijinotify logyijinotify = new Logyijinotify();
            logyijinotify.setAddtime(new Date());
            logyijinotify.setContent(requestString);
            logyijinotify.setType("request");
            logyijinotifyMapper.insert(logyijinotify);
            logger.info("请求参数:{}", requestString);

            post.setEntity(new StringEntity(requestString, ContentType.create(
                    "application/x-www-form-urlencoded", Constants.CHARSET)));
            HttpResponse response = httpClient.execute(post);

            HttpEntity entity = response.getEntity();
            String body = EntityUtils.toString(entity, Constants.CHARSET);
            logyijinotify = new Logyijinotify();
            logyijinotify.setAddtime(new Date());
            logyijinotify.setContent(body);
            logyijinotify.setType("response");
            logyijinotifyMapper.insert(logyijinotify);
            return body;

        } catch (Exception e) {
            logger.error("通讯请求失败", e);
            throw new IllegalStateException("通讯请求失败" + e.getMessage());
        } finally {
            client.getConnectionManager().shutdown();
        }
    }

    protected static String exchange_web(Map<String, String> parameters) {
        HostnameVerifier hostnameVerifier = org.apache.http.conn.ssl.SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER;

        DefaultHttpClient client = new DefaultHttpClient();
        SchemeRegistry registry = new SchemeRegistry();
        SSLSocketFactory socketFactory = SSLSocketFactory.getSocketFactory();
        socketFactory.setHostnameVerifier((X509HostnameVerifier) hostnameVerifier);
        registry.register(new Scheme("https", socketFactory, 443));
        SingleClientConnManager mgr = new SingleClientConnManager(client.getParams(), registry);
        DefaultHttpClient httpClient = new DefaultHttpClient(mgr, client.getParams());

        // Set verifier     
        HttpsURLConnection.setDefaultHostnameVerifier(hostnameVerifier);
        // 请求超时
        client.getParams().setParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, 20000);
        // 读取超时
        client.getParams().setParameter(CoreConnectionPNames.SO_TIMEOUT, 20000);
        HttpPost post = new HttpPost(Constants.get_openapi_address_web());

        try {
            String sign =
                    DigestUtil.digest(parameters, Constants.get_sercurity_key_web(), DigestALGEnum.MD5,
                            "UTF-8");

            String requestString = buildPairs(parameters, sign);
            logger.error("requestString"+requestString);
            Logyijinotify logyijinotify = new Logyijinotify();
            logyijinotify.setAddtime(new Date());
            logyijinotify.setContent(requestString);
            logyijinotify.setType("request");
            logyijinotifyMapper.insert(logyijinotify);
            logger.info("请求参数:{}", requestString);

            post.setEntity(new StringEntity(requestString, ContentType.create(
                    "application/x-www-form-urlencoded", Constants.CHARSET)));
            HttpResponse response = httpClient.execute(post);

            HttpEntity entity = response.getEntity();
            String body = EntityUtils.toString(entity, Constants.CHARSET);
            logyijinotify = new Logyijinotify();
            logyijinotify.setAddtime(new Date());
            logyijinotify.setContent(body);
            logyijinotify.setType("response");
            logyijinotifyMapper.insert(logyijinotify);
            return body;

        } catch (Exception e) {
            logger.error("通讯请求失败", e);
            throw new IllegalStateException("通讯请求失败" + e.getMessage());
        } finally {
            client.getConnectionManager().shutdown();
        }
    }

    /**
     * 将参数组装成HttpEntity需要的形式
     * 
     * @param parameters
     * @param sign
     * @return
     */
    private static String buildPairs(Map<String, String> parameters, String sign) {
        StringBuilder resultStringBuilder = new StringBuilder();
        for (Entry<String, String> e : parameters.entrySet()) {
            try {
                resultStringBuilder.append(e.getKey()).append("=")
                        .append(URLEncoder.encode(e.getValue(), Constants.CHARSET)).append("&");
            } catch (UnsupportedEncodingException e1) {
                logger.error("不支持的字符集", e);
            }
        }
        resultStringBuilder.append("sign=").append(sign);
        String resultString = resultStringBuilder.toString();
        return resultString;
    }

}
